package com.itheima.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.bean.Category;
import com.itheima.bean.Dish;
import com.itheima.bean.Setmeal;
import com.itheima.bean.SetmealDish;
import com.itheima.common.PageParam;
import com.itheima.dao.SetmealDao;
import com.itheima.dto.SetmealDto;
import com.itheima.exception.CustomException;
import com.itheima.service.CategoryService;
import com.itheima.service.SetmealDishService;
import com.itheima.service.SetmealService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class SetmealServiceImpl implements SetmealService {

    @Autowired
    private SetmealDao setmealDao;

    @Autowired
    private SetmealDishService setmealDishService;

    @Lazy
    @Autowired
    private CategoryService categoryService;

    /**
     * 添加套餐
     *   1. 添加套餐需要操作两张表： setmeal  和 setmeal_dish
     *   2. 把套餐本身的主要数据添加到套餐表 setmeal 表
     *
     *   3. 把套餐包含什么菜数据添加到套餐菜品表  setmeal_dish 表
     *
     * @param setmealDto
     * @return
     */
    @Override
    public int add(SetmealDto setmealDto) {


        //1. 添加到套餐表
        int row = setmealDao.insert(setmealDto);

        //2. 添加到套餐菜品表
        if(row > 0 ){
            List<SetmealDish> setmealDishList = setmealDto.getSetmealDishes();

            int row2 = 0 ;

            //2.1 遍历每一道菜
            for (SetmealDish setmealDish : setmealDishList) {

                //2.1.1 设置这个菜属于哪一个套餐
                setmealDish.setSetmealId(setmealDto.getId());

                //2.1.2 添加这个菜到套餐菜品表里面
                row2 += setmealDishService.add(setmealDish);
            }

            return row2 == setmealDishList.size() ? 1 : 0;
        }

        return row;
    }

    /**
     * 根据分类id来查询套餐数据
     *
     * @param categoryId
     * @return
     */
    @Override
    public List<Setmeal> findByCategoryId(long categoryId) {
        //1. 定义条件
        LambdaQueryWrapper<Setmeal> qw = new LambdaQueryWrapper<>();

        //2. 设置查询条件
        qw.eq(Setmeal::getCategoryId , categoryId);

        return setmealDao.selectList(qw);
    }

    /**
     * 分页查询套餐
     *
     * @param pageParam
     * @return
     */
    @Override
    public IPage<SetmealDto> findByPage(PageParam pageParam) {
        //1. 构建分页配置
        IPage<Setmeal> p = new Page<>(pageParam.getPage() , pageParam.getPageSize());

        //2. 构建查询条件
        LambdaQueryWrapper<Setmeal> qw = new LambdaQueryWrapper<>();
        qw.like(pageParam.getName() != null , Setmeal::getName, pageParam.getName());

        //3. 执行分页查询
        IPage<Setmeal> setmealIPage = setmealDao.selectPage(p, qw);

        //====以上的代码仅仅是查询出来的了套餐的数据，但是没有套餐的分类，以及套餐拥有什么菜品！=====

        //4. 遍历每一个套餐
        List<SetmealDto> setmealDtoList = setmealIPage.getRecords().stream().map((setmeal)->{

            //4.1 去查询套餐的分类数据
            Category category = categoryService.findById(setmeal.getCategoryId());

            //TODO: 4.2 去查询套餐有什么菜品

            //4.3 构建SetmealDto ，然后封装数据
            SetmealDto setmealDto = new SetmealDto();

            //4.3.1 封装分类数据
            setmealDto.setCategoryName(category.getName());

            //TODO: 4.3.2 封装菜品数据

            //4.3.3 封装套餐数据
            BeanUtils.copyProperties(setmeal  , setmealDto);

            //4.3.4 返回dto
            return setmealDto;
        }).collect(Collectors.toList());

        //5. 构建IPage<SetmealDto>
        IPage<SetmealDto> dtoIPage = new Page<>();

        //5.1 设置集合数据
        dtoIPage.setRecords(setmealDtoList);

        //5.2 设置总记录数
        dtoIPage.setTotal(setmealIPage.getTotal());


        return dtoIPage;
    }

    /**
     * 删除套餐
     *  1. 不能直接认为就是删除套餐即可，要考虑套餐属于启售状态的情况
     *      1.1 如果套餐属于启售状态，那么就不能删除套餐！
     *      1.2 如果是批量删除的情况，只要有一个属于启售状态，那么就不能删除！
     *  2.  删除套餐的时候，也要考虑去删除套餐菜品表数据。否则后面
     *      套餐已经删除了，但是套餐包含的菜品数据还在！
     *
     * @param ids
     * @return
     */
    @Override
    public int delete(List<Long> ids) {

        //1. 先查询看看，有没有哪个套餐属于启售状态
        // select count(*) from setmeal where status = 1 and id  in (1, ,3 ,5 )   // 1, 3, 5

        //1.1 构建条件对象
        LambdaQueryWrapper<Setmeal> qw = new LambdaQueryWrapper<>();

        //1.2 设置条件
        qw.in(Setmeal::getId , ids);
        qw.eq(Setmeal::getStatus , 1);

        //1.3 执行查询
        int total = setmealDao.selectCount(qw);

        //如果 >  0  则认为是有套餐处于启售状态！
        if(total > 0 ){
            throw  new CustomException("套餐处于启售状态，禁止删除！");
        }

        //2. 如果有就禁止删除，否则就允许去执行删除

        //2.1 删除套餐表数据
        int row1 = setmealDao.deleteBatchIds(ids);

        //2.2 删除套餐菜品表数据
        for (Long id : ids) {
             setmealDishService.deleteBySetmealId(id);
        }

        return row1;
    }

    /**
     * 根据套餐的分类，获取该分类下的套餐
     *
     * @param categoryId
     * @param status
     * @return
     */
    @Override
    public List<Setmeal> findByCategoryId(Long categoryId, Integer status) {
        LambdaQueryWrapper<Setmeal> qw = new LambdaQueryWrapper<>();
        qw.eq(Setmeal::getCategoryId , categoryId );
        qw.eq(Setmeal::getStatus , status );

        return setmealDao.selectList(qw);
    }
	 /**
     * 根据套餐id修改售卖状态
     * @param status
     * @param ids
     */
    @Override
    public void updateSetmealStatusById(Integer status,  List<Long> ids) {
        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.in(ids !=null,Setmeal::getId,ids);
        List<Setmeal> list = setmealDao.selectList(queryWrapper);

        for (Setmeal setmeal : list) {
            if (setmeal != null){
                setmeal.setStatus(status);
                setmealDao.updateById(setmeal);
            }
        }
    }
    /**
     * 回显套餐数据：根据套餐id查询套餐
     * @return
     */
    @Override
    public SetmealDto getDate(Long id) {
        Setmeal setmeal = setmealDao.selectById(id);
        SetmealDto setmealDto = new SetmealDto();
        LambdaQueryWrapper<SetmealDish> queryWrapper = new LambdaQueryWrapper();
        //在关联表中查询，setmealdish
        queryWrapper.eq(id!=null,SetmealDish::getSetmealId,id);

        if (setmeal != null){
            BeanUtils.copyProperties(setmeal,setmealDto);
            List<SetmealDish> list = setmealDishService.list(queryWrapper);
            setmealDto.setSetmealDishes(list);
            return setmealDto;
        }
        return null;
    }

    /**
     * 更新套餐信息，同时更新对应的菜品信息
     *
     * @param setmealDto
     */
    @Override
    @Transactional
    public void updateWithDish(SetmealDto setmealDto) {
        //更新 setmeal 表的基本信息
        setmealDao.updateById(setmealDto);

        //清理当前套餐对应的菜品数据，即 setmeal_dish 表的 delete 操作
        LambdaQueryWrapper<SetmealDish> queryWrapper = new LambdaQueryWrapper<SetmealDish>();
        queryWrapper.eq(SetmealDish::getSetmealId, setmealDto.getId());
        setmealDishService.deleteBySetmealId(setmealDto.getId());

        //添加当前提交的菜品数据，即 setmeal_dish 表的 insert 操作
        List<SetmealDish> mealDishes = setmealDto.getSetmealDishes();

        mealDishes = mealDishes.stream().map((item) -> {
            item.setSetmealId(setmealDto.getId());
            return item;
        }).collect(Collectors.toList());

        for (SetmealDish dish : mealDishes) {
            setmealDishService.add(dish);
        }

    }
}
